package com.ruoyi.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request.Msg;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request.Text;
import com.dingtalk.api.response.*;
import com.dingtalk.api.response.OapiMessageCorpconversationGetsendresultResponse.AsyncSendResult;
import com.dingtalk.api.response.OapiUserListbypageResponse.Userlist;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.CommonStrUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.IDingTalkClientService;
import com.taobao.api.ApiException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class DingTalkClientServiceImpl implements IDingTalkClientService {
    private static final Logger log = LoggerFactory.getLogger(DingTalkClientServiceImpl.class);

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SysDeptMapper deptMapper;
    @Autowired
    private SysUserMapper userMapper;

    private static final String OPEN_DINGTALK_URL = "https://oapi.dingtalk.com";//钉钉接口地址
    private static final String REDIS_DINGTALK_TOKEN_KEY = "dingtalk_access_token";//redis中token前缀
    private static final String SYN_REDIRECT_URI = "";//回调地址
    @Value("${cloudpivot.dingtalk.client.aes_key}")
    private String aesKey;
    @Value("${cloudpivot.dingtalk.client.aes_token}")
    private String aesToken;
    @Value("${cloudpivot.dingtalk.client.callback_tag}")
    private String[] callbackTag;
    @Value("${cloudpivot.dingtalk.client.callback_url}")
    private String callbackUrl;
    @Value("${cloudpivot.dingtalk.client.diff_token_expire_time:60}")
    private Long diffTokenExpireTime;

    @Value("${cloudpivot.dingtalk.corpId}")
    private String corpId;
    @Value("${cloudpivot.dingtalk.appKey}")
    private String appKey;
    @Value("${cloudpivot.dingtalk.appSecret}")
    private String appSecret;
    @Value("${cloudpivot.dingtalk.agentId}")
    private String agentId;

    public synchronized String getDingTalkAccessToken() {
        String key = REDIS_DINGTALK_TOKEN_KEY + corpId;
        String accessToken = this.redisTemplate.opsForValue().get(key);
        if (!StringUtils.isEmpty(accessToken)) {
            return accessToken;
        } else {
            DefaultDingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/gettoken");
            OapiGettokenRequest request = new OapiGettokenRequest();
            log.info("获取到的appkey:" + appKey);
            log.info("获取到的appsecret:" + appSecret);
            request.setAppkey(appKey);
            request.setAppsecret(appSecret);
            request.setHttpMethod("GET");

            try {
                OapiGettokenResponse response = client.execute(request);
                if (response.isSuccess()) {
                    log.info("获取钉钉Token成功");
                    this.redisTemplate.opsForValue().set(key, response.getAccessToken(), response.getExpiresIn() - this.diffTokenExpireTime, TimeUnit.SECONDS);
                    return response.getAccessToken();
                } else {
                    log.warn("获取钉钉Token失败，错误信息：" + response.getErrmsg());
                }
            } catch (ApiException var10) {
                log.error("获取钉钉Token异常，异常信息：" + var10.getErrMsg());
            }
        }
        return null;
    }


    public boolean syncDepartmentAndUsers() {
        DingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/department/list");
        OapiDepartmentListRequest oapiDepartmentListRequest = new OapiDepartmentListRequest();
        oapiDepartmentListRequest.setFetchChild(true);

        try {
            OapiDepartmentListResponse oapiDepartmentListResponse = client.execute(oapiDepartmentListRequest, this.getDingTalkAccessToken());

            List<OapiDepartmentListResponse.Department> dingDepartmentList = Lists.newArrayList();
            if (oapiDepartmentListResponse.isSuccess()) {
                dingDepartmentList = oapiDepartmentListResponse.getDepartment();
                if(dingDepartmentList != null && !dingDepartmentList.isEmpty()){
                    for(OapiDepartmentListResponse.Department department : dingDepartmentList){
                        //部门操作
                        SysDept sysDept = deptMapper.selectDeptById(department.getId());
                        if(sysDept != null){
                            //更新部门
                            sysDept.setDeptName(department.getName());
                            if(department.getParentid() != null){
                                //父节点不为空
                                sysDept.setParentId(department.getParentid());
                            }
                            sysDept.setUpdateBy("admin");
                            sysDept.setUpdateTime(new Date());
                            deptMapper.updateDept(sysDept);
                        }else {
                            //新增部门
                            sysDept = new SysDept();
                            sysDept.setDeptId(department.getId());
                            sysDept.setParentId(department.getParentid());
                            sysDept.setDeptName(department.getName());
                            sysDept.setDelFlag("0");
                            sysDept.setStatus("0");
                            sysDept.setCreateBy("admin");
                            sysDept.setCreateTime(new Date());

                            deptMapper.insertDept(sysDept);
                        }
                        //用户操作
                        //根据部门ID获取用户列表
                        OapiUserListResponse userListResponse = this.getUserList(sysDept.getDeptId());

                        if (userListResponse.isSuccess()) {
                            List<OapiUserListResponse.Userlist> userlist = userListResponse.getUserlist();
                            if(userlist != null && !userlist.isEmpty()){
                                for (OapiUserListResponse.Userlist dingtalkUser : userlist){

                                    String JobNumber = null;

                                    if (dingtalkUser.getJobnumber() != null && !dingtalkUser.getJobnumber().trim().equals("")){
                                        JobNumber = dingtalkUser.getJobnumber();
                                    }else{
                                        JobNumber = dingtalkUser.getUserid();
                                    }
                                    SysUser user = userMapper.selectUserByLoginName(JobNumber);

                                    if(user == null){
                                        //新增用户
                                        user = new SysUser();
                                        user.setDelFlag("0");
                                        user.setStatus("0");
                                        user.setSalt(ShiroUtils.randomSalt());
                                        user.setPassword("123456");
                                        user.setLoginName(JobNumber);
                                        user.setPassword(new Md5Hash(user.getLoginName() + user.getPassword() + user.getSalt()).toHex());
                                        user.setCreateBy("admin");
                                        user.setCreateTime(new Date());
                                    }else {
                                        user.setUpdateBy("admin");
                                        user.setUpdateTime(new Date());
                                    }
                                    user.setEmail(dingtalkUser.getEmail());
                                    user.setDingtalkUserId(dingtalkUser.getUserid());
                                    user.setDeptId(sysDept.getDeptId());
                                    user.setUserName(dingtalkUser.getName());
                                    user.setPhonenumber(dingtalkUser.getMobile());
                                    if(user.getUserId() == null){
                                        userMapper.insertUser(user);
                                    }else {
                                        userMapper.updateUser(user);
                                    }
                                }
                            }
                        }

                    }
                }
            }
        } catch (ApiException var5) {
            log.error("获取钉钉部门列表异常，异常信息：" + var5.getErrMsg());
            return false;
        }
        return true;
    }

    public String sendTextMessageToDingTalk(String receivers, String content) {
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setUseridList(receivers);
        request.setAgentId(Long.valueOf(agentId));
        request.setToAllUser(false);
        Msg msg = new Msg();
        msg.setText(new Text());
        msg.getText().setContent(content);
        msg.setMsgtype("text");
        request.setMsg(msg);
        return this.execute(request);
    }
    public String sendMarkDownMessageToDingTalk(String receivers, String title,String text) {
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setUseridList(receivers);
        request.setAgentId(Long.valueOf(agentId));
        request.setToAllUser(false);
        Msg msg = new Msg();
        msg.setMsgtype("markdown");
        OapiMessageCorpconversationAsyncsendV2Request.Markdown markdownMsg = new OapiMessageCorpconversationAsyncsendV2Request.Markdown();
        markdownMsg.setTitle(title);
        markdownMsg.setText(text);
        msg.setMarkdown(markdownMsg);
        request.setMsg(msg);
        return this.execute(request);
    }
    public String sendMarkDownMessageToDingTalkbyDept(String deptReceivers, String title,String text) {
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setDeptIdList(deptReceivers);
        request.setAgentId(Long.valueOf(agentId));
        request.setToAllUser(false);
        Msg msg = new Msg();
        msg.setMsgtype("markdown");
        OapiMessageCorpconversationAsyncsendV2Request.Markdown markdownMsg = new OapiMessageCorpconversationAsyncsendV2Request.Markdown();
        markdownMsg.setTitle(title);
        markdownMsg.setText(text);
        msg.setMarkdown(markdownMsg);
        request.setMsg(msg);
        return this.execute(request);
    }
    public String execute(OapiMessageCorpconversationAsyncsendV2Request request) {
        DefaultDingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/topapi/message/corpconversation/asyncsend_v2");

        try {
            OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request, this.getDingTalkAccessToken());
            if (log.isDebugEnabled()) {
                log.debug("response = {}.", JSON.toJSONString(response));
            }

            if (null != response.getTaskId()) {
                log.info("获取消息的任务: body--{},taskId--{},msg--{},agent--{},userid--{} ", new Object[]{response.getBody(), response.getTaskId(), response.getParams().get("msg"), response.getParams().get("agent_id"), response.getParams().get("userid_list")});
                return String.valueOf(response.getErrmsg());
            } else {
                log.error("获取消息的任务id 失败 - {}", response.getErrmsg());
            }
        } catch (ApiException var5) {
            log.error("获取消息的任务id 异常");
        }
        return null;
    }

    public AsyncSendResult getMessageResult(String taskId) {
        if (!StringUtils.isBlank(agentId) && !StringUtils.isBlank(taskId)) {
            DingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/topapi/message/corpconversation/getsendresult");
            OapiMessageCorpconversationGetsendresultRequest request = new OapiMessageCorpconversationGetsendresultRequest();
            request.setAgentId(Long.valueOf(agentId));
            request.setTaskId(Long.valueOf(taskId));

            try {
                OapiMessageCorpconversationGetsendresultResponse response = (OapiMessageCorpconversationGetsendresultResponse)client.execute(request, this.getDingTalkAccessToken());
                if (response.isSuccess()) {
                    return response.getSendResult();
                } else {
                    log.debug("获取钉钉消息taskId ={}推送结果失败", taskId);
                    return null;
                }
            } catch (ApiException var7) {
                log.error("获取钉钉消息taskId ={}推送结果异常", taskId);
            }
        } else {
            return null;
        }
        return null;
    }

    public OapiCallBackRegisterCallBackResponse registerCallBackUrl() {
        DingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/call_back/register_call_back");
        OapiCallBackRegisterCallBackRequest request = new OapiCallBackRegisterCallBackRequest();
        List list = Arrays.asList(this.callbackTag);
        String synRedirectUri = this.getSynRedirectUri();
        request.setCallBackTag(list);
        request.setAesKey(this.aesKey);
        request.setToken(this.aesToken);
        String callbackServerUrl = this.getCallbackServerUrl(this.corpId, synRedirectUri);
        log.info("【注册钉钉增量同步回调地址】:" + callbackServerUrl);
        request.setUrl(callbackServerUrl);

        try {
            OapiCallBackRegisterCallBackResponse response = client.execute(request, this.getDingTalkAccessToken());
            if (response.isSuccess()) {
                log.info("注册dingtalk事件通知URL成功");
                return response;
            } else {
                log.warn("注册dingtalk事件通知URL失败，错误信息：" + response.getErrmsg() + "，corpId:" + this.corpId);
            }
        } catch (ApiException var8) {
            log.error("注册dingtalk事件通知URL异常，异常信息：" + var8.getErrMsg());
        }
        return null;
    }

    private String getCallbackServerUrl(String corpId, String synRedirectUri) {
        return CommonStrUtils.handleUrlPath(synRedirectUri) + this.callbackUrl + "/" + corpId;
    }

    private String getSynRedirectUri() {
        return CommonStrUtils.handleUrlPath(SYN_REDIRECT_URI);
    }

    public String getSignature(String appsecret) {
        String signature = null;
        String stringToSign = String.valueOf(System.currentTimeMillis());

        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(appsecret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signatureBytes = mac.doFinal(stringToSign.getBytes("UTF-8"));
            signature = new String(Base64.encodeBase64(signatureBytes));
        } catch (Exception var6) {
            var6.printStackTrace();
        }

        return signature;
    }

    public synchronized OapiUserGetResponse getUserDetail(String userId) {
        DingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL +  "/user/get");
        OapiUserGetRequest oapiUserGetRequest = new OapiUserGetRequest();
        oapiUserGetRequest.setUserid(userId);
        oapiUserGetRequest.setHttpMethod("GET");

        try {
            OapiUserGetResponse oapiUserGetResponse = client.execute(oapiUserGetRequest, this.getDingTalkAccessToken());
            if (oapiUserGetResponse.isSuccess()) {
                log.info("获取钉钉用户信息成功");
                return oapiUserGetResponse;
            } else {
                log.warn("获取钉钉用户信息失败，错误信息：" + oapiUserGetResponse.getErrmsg());
            }
        } catch (ApiException var6) {
            log.error("获取钉钉用户信息异常，异常信息：" + var6.getErrMsg());
        }
        return null;
    }

    /**
     * 根据部门获取
     * @param departmentId
     * @return
     */
    public OapiUserListResponse getUserList(Long departmentId) {
        DingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/user/list");
        OapiUserListRequest oapiUserListRequest = new OapiUserListRequest();
        oapiUserListRequest.setDepartmentId(departmentId);

        try {
            OapiUserListResponse oapiUserListResponse = client.execute(oapiUserListRequest, this.getDingTalkAccessToken());
            if (oapiUserListResponse.isSuccess()) {
                return oapiUserListResponse;
            } else {
                log.warn("获取钉钉用户列表失败，错误信息：" + oapiUserListResponse.getErrmsg());
            }
        } catch (ApiException var6) {
            log.error("获取钉钉用户列表异常，异常信息：" + var6.getErrMsg());
        }
        return null;
    }

    /**
     * 根据部门分页查询
     * @param departmentId
     * @return
     */
    public List<Userlist> getUserListByPage(Long departmentId) {
        List<Userlist> responses = Lists.newArrayList();
        boolean hasMore = true;
        int i = 0;
        int intSize = 100;
        Long size = 100L;
        Long nextCursor = 0L;

        while(hasMore) {
            OapiUserListbypageResponse response = this.getUserListByPage(departmentId, nextCursor, size);
            if (!response.isSuccess()) {
                log.error("获取部门用户列表异常：{}", response.getErrmsg());
            }

            hasMore = response.getHasMore();
            ++i;
            int offset = i * intSize;
            nextCursor = (long)offset;
            responses.addAll(response.getUserlist());
            log.info("nextCursor的数据：-{}", nextCursor);
        }
        return responses;
    }

    public OapiUserListbypageResponse getUserListByPage(Long departmentId, Long nextCusor, Long size) {
        DingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/user/listbypage");
        OapiUserListbypageRequest request = new OapiUserListbypageRequest();
        request.setDepartmentId(departmentId);
        request.setSize(size);
        request.setOffset(nextCusor);

        try {
            OapiUserListbypageResponse response = client.execute(request, this.getDingTalkAccessToken());
            return response;
        } catch (ApiException var8) {
            log.error("获取钉钉角色下员工列表异常，异常信息是：" + var8.getErrMsg());
        }
        return null;
    }

    public synchronized OapiDepartmentGetResponse getDepartmentDetail(String departmentId) {
        DingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/department/get");
        OapiDepartmentGetRequest oapiDepartmentGetRequest = new OapiDepartmentGetRequest();
        oapiDepartmentGetRequest.setId(departmentId);

        try {
            OapiDepartmentGetResponse oapiDepartmentGetResponse = (OapiDepartmentGetResponse)client.execute(oapiDepartmentGetRequest, this.getDingTalkAccessToken());
            if (oapiDepartmentGetResponse.isSuccess()) {
                return oapiDepartmentGetResponse;
            } else {
                log.info("获取钉钉部门信息失败，错误信息：" + oapiDepartmentGetResponse.getErrmsg());
            }
        } catch (ApiException var6) {
            log.error("获取钉钉部门信息异常，异常信息：" + var6.getErrMsg());
        }
        return null;
    }

    public OapiDepartmentListParentDeptsByDeptResponse listParentDeptsByDeptId(String deptId) {
        DingTalkClient client = new DefaultDingTalkClient(OPEN_DINGTALK_URL + "/department/list_parent_depts_by_dept");
        OapiDepartmentListParentDeptsByDeptRequest request = new OapiDepartmentListParentDeptsByDeptRequest();
        request.setId(deptId);
        request.setHttpMethod("GET");
        OapiDepartmentListParentDeptsByDeptResponse response = null;

        try {
            response = (OapiDepartmentListParentDeptsByDeptResponse)client.execute(request, this.getDingTalkAccessToken());
        } catch (ApiException var7) {
            log.error("获取钉钉部门信息异常，异常信息：" + var7.getErrMsg());
            if (response == null) {
                response = new OapiDepartmentListParentDeptsByDeptResponse();
                response.setErrcode(-1L);
                response.setErrmsg(var7.getCause().getMessage());
            }
        }

        return response;
    }
}
